#include <boost/lambda/lambda.hpp>

#include "indexator.h"

using namespace Porridge;

Indexator::Indexator()
{
    setQueryThreadLimit();
}

Indexator::~Indexator()
{
    //wait for uncanceled threads
    m_ThreadGroup.join_all();
}

void Indexator::doWork(const std::string & query)
{
    PGQuery * queryThread = NULL;
    if(!m_PGQueryQueue.try_pop(queryThread))
    {
        // no ready to use thread objects
        std::cout << "No ready to use thread objects. ";
        if(m_PGQueryVector.size() < m_queryThreadLimit)
        {
            std::cout << "Create new thread object" << std::endl;
            m_PGQueryVector.push_back(boost::shared_ptr<PGQuery>(new PGQuery(m_connectionInfo, &m_PGQueryQueue)));
            queryThread = m_PGQueryVector.back().get();
        }
        else
        {
            //cannot create new thread object because of limit exceed
            //wait for the free thread object
            std::cout << "Wait..." << std::endl;
            //TODO append wait time?
            m_PGQueryQueue.lock_and_pop(queryThread);
        }
    }
    //set query string for execution
    queryThread->setQuery(query);
    //run query in separete thread
    m_ThreadGroup.create_thread(boost::bind(&PGQuery::performQuery, queryThread));
}

void Indexator::operator ()(const std::string & tableName)
{
    for(auto &query: m_processingQueries)
        doWork("select * from " + query + "(" + tableName + ")");
}

void Indexator::setQueryThreadLimit(size_t limit)
{
    if(limit)
    {
        m_queryThreadLimit = limit;
        return;
    }
    size_t hardware_limit = boost::thread::hardware_concurrency();
    m_queryThreadLimit = hardware_limit ? hardware_limit : 1;
}
